package biz.datalk.industrialland.admin.modules.online.dynform.service.impl;

import biz.datalk.commons.helper.collection.ListHelper;
import biz.datalk.industrialland.admin.modules.common.servie.ICommonService;
import biz.datalk.industrialland.admin.modules.online.config.cfg.enums.SqlOperationTypeEnum;
import biz.datalk.industrialland.admin.modules.online.config.hook.HookSplicingResult;
import biz.datalk.industrialland.admin.modules.online.config.hook.HookValidParamsResult;
import biz.datalk.industrialland.admin.modules.online.config.hook.IDynfromHook;
import biz.datalk.industrialland.admin.modules.online.config.util.DynformFieldUtil;
import biz.datalk.industrialland.admin.modules.online.config.util.HookUtil;
import biz.datalk.industrialland.admin.modules.online.dynform.pojo.dto.DynformAutoDTO;
import biz.datalk.industrialland.admin.modules.online.dynform.pojo.dto.DynformFieldDTO;
import biz.datalk.industrialland.admin.modules.online.dynform.pojo.po.DynformHead;
import biz.datalk.industrialland.admin.modules.online.dynform.pojo.vo.DynformFieldVo;
import biz.datalk.industrialland.admin.modules.online.dynform.service.IDynformCacheService;
import biz.datalk.industrialland.admin.modules.online.dynform.service.IDynformServices;
import biz.datalk.industrialland.admin.modules.online.dynform.service.IDynfromAutoApiService;
import biz.datalk.industrialland.common.def.enums.DBYNEnum;
import biz.datalk.industrialland.common.exception.ServiceException;
import biz.datalk.industrialland.common.result.UnifyResult;
import biz.datalk.industrialland.common.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 *
 *
 * @author tarofang@163.com
 * @date 2020-04-07
 *
 */
@Slf4j
@Service
public class DynfromAutoApiServiceImpl implements IDynfromAutoApiService {

    @Autowired
    private IDynformServices dynformServices;

    @Autowired
    private ICommonService commonService;

    @Value(value = "${core.file.view-prefix}")
    private String previewPrefix;

    @Autowired
    private IDynformCacheService dynformCacheService;

    @Override
    public List<DynformFieldVo> getItems(String tableId, String id, boolean needGroup) {

        DynformHead table = dynformServices.selectByPk(tableId);
        if (table == null) {
            throw new ServiceException("未知表单");
        }

        String tableName = StringUtils.trimToEmpty(table.getTableName());
        if (StringUtils.isEmpty(tableName)) {
            throw new ServiceException("未知填报表单");
        }

        List<DynformFieldDTO> fieldList = dynformCacheService.getItems(tableId);

        //List<DynformFieldDTO> fieldList = dynformServices.selectByTableId(table.getId(), Boolean.TRUE);
        if (CollectionUtils.isEmpty(fieldList)) {
            throw new ServiceException("未知表单，无填报内容");
        }

        // 表单字段(添加、编辑)
        List<DynformFieldDTO> formFields = new ArrayList<>();
        for (DynformFieldDTO field : fieldList) {
            //field.setFieldNameHump(FieldUtil.underline2Hump(field.getFieldName()));
            //if (StringUtils.equals(field.getFieldIsPk(), DBYNEnum.Y.name()) && !StringUtils.equals(field.getPageIsShow(), DBYNEnum.Y.name())) {
            //    formFields.add(field);
            //    continue;
            //}
            if (StringUtils.equals(field.getPageIsShow(), DBYNEnum.Y.name())) {
                formFields.add(field);
            }
        }

        List<DynformFieldVo> resList = new ArrayList<>();
        DynformFieldVo vo = null;
        for (DynformFieldDTO field : formFields) {
            vo = new DynformFieldVo();
            BeanUtils.copyProperties(field, vo);
            if (vo.getDicts() == null) {
                vo.setDicts(new ArrayList<>());
            }
            // 设置默认值
            vo.setFieldContent(field.getPageContentDef());
            // 设置提示值
            resList.add(vo);
        }


        if (StringUtils.isEmpty(id)) {
            return needGroup ? DynformFieldUtil.group(resList) : resList;
        }

        // 获取数据
        ListHelper listHelper = ListHelper.create();
        List<String> fieldNames = listHelper.getValList(resList, "getFieldName", DynformFieldVo.class, String.class);
        String fieldCombine = listHelper.combine(fieldNames, ",");

        String sql = String.format("SELECT %s FROM %s WHERE id=?", fieldCombine, tableName);
        Map<String, Object> data = getData(sql, id);
        if (MapUtils.isEmpty(data)) {
            return needGroup ? DynformFieldUtil.group(resList) : resList;
        }

        HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
        String contextPath = request.getContextPath();


        String fieldContent, fieldType, fieldName;
        Object obj;
        for (DynformFieldVo fieldVo : resList) {
            fieldType = fieldVo.getFieldType();
            fieldName = fieldVo.getFieldName();
            obj = data.get(fieldName);
            if (StringUtils.equalsAnyIgnoreCase(fieldType, "datetime", "timestamp")) {
                if (obj instanceof Date) {
                    if (StringUtils.equalsIgnoreCase(fieldVo.getPageShowType(), "date")) {
                        fieldVo.setFieldContent(DateFormatUtils.format((Date) obj, "yyyy-MM-dd"));
                    }
                    if (StringUtils.equalsIgnoreCase(fieldVo.getPageShowType(), "datetime")) {
                        fieldVo.setFieldContent(DateFormatUtils.format((Date) obj, "yyyy-MM-dd HH:mm:ss"));
                    }
                } else {
                    fieldContent = MapUtils.getString(data, fieldName, "");
                    fieldVo.setFieldContent(fieldContent);
                }
                continue;
            }
            if (StringUtils.equalsAnyIgnoreCase(fieldType, "text", "mediumtext", "varchar", "char")) {
                fieldContent = MapUtils.getString(data, fieldName, "");
                fieldVo.setFieldContent(fieldContent);
                if (StringUtils.equalsIgnoreCase(fieldVo.getPageShowType(), "image")) {
                    String[] split = StringUtils.split(fieldContent, ",");
                    fieldVo.setFiles(ArrayUtils.isEmpty(split) ? new ArrayList<>() : Arrays.asList(split));
                    if (ArrayUtils.isNotEmpty(split)) {
                        List<String> previewUrls = new ArrayList<>();
                        for (String path : split) {
                            previewUrls.add(getPreviewPath(path, contextPath));
                        }
                        fieldVo.setImgPreviewPath(previewUrls);
                    }
                }
            }
        }

        return needGroup ? DynformFieldUtil.group(resList) : resList;
    }


    private String getPreviewPath(String relativePath, String contextPath) {
        String ctxp = "/".equals(contextPath) ? "" : contextPath;
        String path = relativePath.startsWith("/") ? relativePath.substring(1) : relativePath;
        String prefix = StringUtils.trimToEmpty(previewPrefix);
        prefix = prefix.endsWith("/") ? prefix.substring(0, prefix.length() - 1) : prefix;
        return prefix + ctxp + "/sys/common/view/" + path;
    }

    @Override
    public UnifyResult submit(DynformAutoDTO dynformAutoDTO) {
        String tableId = StringUtils.trimToEmpty(dynformAutoDTO.getTableId());
        DynformHead table = dynformServices.selectByPk(tableId);
        if (table == null) {
            log.debug("Invalid talbleId: [{}]", tableId);
            return UnifyResult.fail("提交的数据有误");
        }
        String tableName = StringUtils.trimToEmpty(table.getTableName());
        if (StringUtils.isEmpty(tableName)) {
            return UnifyResult.fail("未知填报表单");
        }

        //List<DynformFieldDTO> fieldList = dynformServices.selectByTableId(table.getId(), Boolean.TRUE);
        List<DynformFieldDTO> fieldList = dynformCacheService.getItems(tableId);
        if (CollectionUtils.isEmpty(fieldList)) {
            throw new ServiceException("未知表单，无填报内容");
        }

        String id = StringUtils.trimToEmpty(dynformAutoDTO.getId());
        boolean isUpdate = StringUtils.isNotEmpty(id);

        IDynfromHook hook = HookUtil.newInstance(table.getHookImplClass());
        if (isUpdate) {
            hook.beforeUpdate(dynformAutoDTO);
        } else {
            hook.beforeInsert(dynformAutoDTO);
        }

        HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
        Map<String, String> paramsMap = hook.parseParams(dynformAutoDTO, request, table, fieldList, isUpdate ? SqlOperationTypeEnum.UPDATE : SqlOperationTypeEnum.INSERT);
        if (paramsMap == null || paramsMap.isEmpty()) {
            log.debug("Invalid params: [{}]", dynformAutoDTO.getParams());
            return UnifyResult.fail("提交的数据有误");
        }

        // 参数验证
        HookValidParamsResult validParamsResult = hook.validParams(dynformAutoDTO, table, fieldList, paramsMap, isUpdate ? SqlOperationTypeEnum.UPDATE : SqlOperationTypeEnum.INSERT);

        validParamsResult = hook.beforeExecSQL(validParamsResult, dynformAutoDTO, table, fieldList, paramsMap, isUpdate ? SqlOperationTypeEnum.UPDATE : SqlOperationTypeEnum.INSERT);

        // @formatter:off
        HookSplicingResult hookSplicingResult = isUpdate
                ? hook.splicingUpdateSql(table, dynformAutoDTO, fieldList, validParamsResult)
                : hook.splicingInsertSql(table, dynformAutoDTO, fieldList, validParamsResult);
        // @formatter:on
        Integer resInt = (Integer) hook.execSql(hookSplicingResult.getSql(), hookSplicingResult.getArgs(), isUpdate ? SqlOperationTypeEnum.UPDATE : SqlOperationTypeEnum.INSERT);

        UnifyResult result = hook.saveDBSuccess(resInt, dynformAutoDTO, table, fieldList, paramsMap, isUpdate ? SqlOperationTypeEnum.UPDATE : SqlOperationTypeEnum.INSERT);

        return isUpdate ? hook.afterUpdate(dynformAutoDTO, result) : hook.afterInsert(dynformAutoDTO, result);
    }

    private Map<String, Object> getData(String sql, Object... objs) {
        try {
            return commonService.findOneForJdbc(sql, objs);
        } catch (Exception ex) {
            log.warn(ex.getMessage());
            return null;
        }
    }
}
